/**
  ETFDAQ Project
  \class TAMsg
  \brief to print runtime message
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2024-08-11
  \date 2024-08-11 last modified

  \copyright Copyright (c) 2021-2024 IMP-CAS with LGPLv3 LICENSE
*/

#include <ctime>
#include <stdarg.h> // variable arguments handle function declarations
#include <cstdlib>
#include <chrono>
#include <signal.h> // for kill
#include <unistd.h> // for getpid
#include <errno.h> // for errno
#include <cstring> // for strerror

#include "TAMsg.h"
#include "TAMutexLocker.h"

using std::cout;
using std::endl;

// assignment and definition
char TAMsg::kMsg[512];
bool TAMsg::kIsVerbose = false;
bool TAMsg::kIsSilent = false;
bool TAMsg::kIsDebug = true;
bool TAMsg::kIsInterrupted = false;
std::mutex TAMsg::kMutex;
std::mutex TAMsg::kMutexSignal;
int TAMsg::kSignal = -1;

TAMsg::TAMsg(){}
TAMsg::~TAMsg(){}

// just like sprintf
const char *TAMsg::Form(const char *fmt, ...){
	strcpy(kMsg, "");
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	vsprintf(kMsg, fmt, arg_ptr);
	va_end(arg_ptr);
	return kMsg;
} // end member function Form

void TAMsg::Info(const char *cname, const char *fmt, ...){
	if(kIsSilent) return;

	char msg[1024], omsg[1024];
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	sprintf(msg, "  ETFDaq-Info: \033[32;1m[%s]\033[36;1m %s\n\033[0m", cname, fmt);
	vsprintf(omsg, msg, arg_ptr);
	va_end(arg_ptr);
	cout << omsg;
} // end member function Info

void TAMsg::Error(const char *cname, const char *fmt, ...){
	static bool nomore = false;
	if(nomore) return;

	char msg[1024], omsg[1024];
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	sprintf(msg, "\033[31;1m  ETFDaq-Error: \033[0m\033[33;1m[%s]\033[0m\033[31;1m %s\n\033[0m", cname, fmt);
	vsprintf(omsg, msg, arg_ptr);
	va_end(arg_ptr);
	cout << omsg;

	// exit(1);
	// select repeatability
	if(!nomore){
		cout << "[q]: abort, [n]: do not stop any more, others: continue > " << std::flush;
		string str;
		std::getline(std::cin, str);
		if(!str.empty() && (str.c_str())[0] == 'q'){
			cout << "Aborting ETF...\n";
			exit(1);
		}
		else if(!str.empty() && (str.c_str())[0] == 'n'){
			nomore = true;
		}
		cout << std::endl;
	}
} // end member function Error

void TAMsg::Warn(const char *cname, const char *fmt, ...){
	static bool nomore = false;
	if(nomore) return;

	char msg[1024], omsg[1024];
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	sprintf(msg, "\033[36;1m  ETFDaq-Warning: "
		"\033[0m\033[33;1m[%s]\033[0m\033[34;1m %s\n\033[0m", cname, fmt);
	vsprintf(omsg, msg, arg_ptr);
	va_end(arg_ptr);
	cout << omsg;

	// // select repeatability
	// if(!nomore){
	// 	cout << "[q]: abort, [n]: do not stop any more, others: continue > " << std::flush;
	// 	string str;
	// 	std::getline(std::cin, str);
	// 	if(!str.empty() && (str.c_str())[0] == 'q'){
	// 		cout << "Aborting ETF...\n";
	// 		exit(1);
	// 	}
	// 	else if(!str.empty() && (str.c_str())[0] == 'n'){
	// 		nomore = true;
	// 	}
	// 	cout << std::endl;
	// } // end if
} // end member function Warn

void TAMsg::Debug(const char *cname, const char *fmt, ...){
	if(!kIsDebug) return;

	char msg[1024], omsg[1024];
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	sprintf(msg, "  ETFDaq-Debug: \033[33;1m[%s]\033[0m %s\n", cname, fmt);
	vsprintf(omsg, msg, arg_ptr);
	va_end(arg_ptr);
	cout << omsg;
} // end member function Debug

void TAMsg::ConfigInfo(const char *cname, const char *fmt, ...){
	if(!kIsVerbose) return;

	char msg[1024], omsg[1024];
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	sprintf(msg, "\033[32;1m  ETFDaq-ConfigInfo: \033[0m\033[33;1m[%s]\033[0m\033[32;1m %s\n\033[0m", cname, fmt);
	vsprintf(omsg, msg, arg_ptr);
	va_end(arg_ptr);
	cout << omsg;
} // end member function ConfigInfo

void TAMsg::ShowPoint(const char *msg, const double *p, const int len){
	for(int i = 0; i < len; i++)
		cout << msg << "[" << i << "]: " << p[i] << "\t";
} // end member function ShowPoint

// isName: no comma in the returned string, suitable for path and file name
// isName = true: YYYYMMDD_HHMM
const char *TAMsg::time0(bool isName){
	time_t tt = time(NULL);
	tm *t = localtime(&tt);
	static char ttt[128];
	if(!isName) sprintf(ttt, "%d-%02d-%02d_%02d:%02d", t->tm_year + 1900,
	 t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min);
	else sprintf(ttt, "%d%02d%02d_%02d%02d", t->tm_year + 1900,
	 t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min);
	return ttt;
} // end member function time0

// isName: no comma in the returned string, suitable for path and file name
// isName = true: YYYYMMDD_HHMMSS
const char *TAMsg::sec0(bool isName){
	time_t tt = time(NULL);
	tm *t = localtime(&tt);
	static char ttt[128];
	if(!isName) sprintf(ttt, "%d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900,
		t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
	else sprintf(ttt, "%d%02d%02d_%02d%02d%02d", t->tm_year + 1900,
		t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
	return ttt;
} // end member function sec0

// interval from t0 to now in HH:MM:SS
const char *TAMsg::secInterval(time_t t0){
	const int dt = time(NULL) - t0;
	// get the time zone first //
	static char ttt[128];
	sprintf(ttt, "%02d:%02d:%02d", dt/3600, (dt%3600)/60, dt%60);
	return ttt;
} // end member function secInterval

void TAMsg::LogoPlain(string &s){
	s += "\n";
	// s += " -----------------------------------------------------------\n";
	// s += " |   EEEEEEE  TTTTTTT  FFFFFF     A                        |\n";
	// s += " |   E           T     F         A A                       |\n";
	// s += " |   EEEEE       T     FFFF     A   A    n n n   a a a     |\n";
	// s += " |   E           T     F       A  A  A   n   n   a   a     |\n";
	// s += " |   EEEEEE X    T     F      A       A  n   n   a a a a   |\n";
	// s += " -----------------------------------------------------------\n";
	s += "---------- ETFDaq Project (ETFAna's sub-project) -------------\n";
	s += "----------------- Version 1.0.1 Mar. 31, 2025 ----------------\n";
	s += "----------- https://gitee.com/asiarabbit/etfdaq ----------\n";
	s +=       "______Author: SUN Yazhou, asia.rabbit@163.com______\n";
	s += '\n';
} // end member function LogoPlain

void TAMsg::Logo(std::ostream &os){
	os << "\033[32;1m\n";
	os << " -----------------------------------------------------------" << endl;
	os << " |   EEEEEEE  TTTTTTT  FFFFFF     A                        |" << endl;
	os << " |   E           T     F         A A                       |" << endl;
	os << " |   EEEEE       T     FFFF     A   A    n n n   a a a     |" << endl;
	os << " |   E           T     F       A  A  A   n   n   a   a     |" << endl;
	os << " |   EEEEEE \033[31;1mX\033[32;1m    T     F      A       A  n   n   a a a a   |" << endl;
	os << " -----------------------------------------------------------" << endl;
	os << "\033[0m";
	os << "------------ ETFDaq Project (ETFAna's sub-project) -----------" << endl;
	os << "----------------- Version 1.0.1 Mar. 31, 2025 ----------------" << endl;
	os << "------------- https://gitee.com/asiarabbit/etfdaq ------------" << endl;
	os << "____________Author: SUN Yazhou, asia.rabbit@163.com___________" << endl;
} // end member function Logo

// a clock in ms()
time_t TAMsg::ms(){
	return std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
} // end member function ms

// time w.r.t the program execution time
time_t TAMsg::ms1(){
	static const time_t tt0 = ms();
	return ms() - tt0;
} // end member function ms1

void TAMsg::SetInterrupted(){
	TAMutexLocker lock(&kMutex);
	kIsInterrupted = true;
} // end member function SetInterrupted

bool TAMsg::Interrupted(){
	TAMutexLocker lock(&kMutex);
	return kIsInterrupted;
} // end member function Interrupted

int TAMsg::Signal(){
	TAMutexLocker lock(&kMutexSignal);
	return kSignal;
} // end member function Signal
void TAMsg::ClearSignal(){
	TAMutexLocker lock(&kMutexSignal);
	kSignal = -1;
} // end member function ClearSignal
void TAMsg::SetSignal(int s){
	TAMutexLocker lock(&kMutexSignal);
	kSignal = s;
} // end member function SetSignal

void TAMsg::Print32(uint32_t d){
  cout << "0b ";
  for(int i = 32; i--;){
    if(d & (1<<i)) cout << '1';
    else cout << '0';
    if(i%8 == 0) cout << "  ";
    else if(i%4 == 0) cout << ' ';
  } // end for over i
  cout << endl;
} // end member function Print32
void TAMsg::Print16(uint16_t d){
  cout << "0b ";
  for(int i = 16; i--;){
    if(d & (1<<i)) cout << '1';
    else cout << '0';
    if(i%8 == 0) cout << "  ";
    else if(i%4 == 0) cout << ' ';
  } // end for over i
  cout << endl;
} // end member function Print16
